﻿using Game;
using Engine;
using Engine.Graphics;
using Engine.Media;
using System;
using System.Xml.Linq;
using System.Collections.Generic;
using Mekiasm.Common;
using GameEntitySystem;
using TemplatesDatabase;
using static Game.TerrainUpdater;

namespace Mekiasm
{
    public class MekModLoader : ModLoader
    {
        public class FaceDraw
        {
            public PrimitivesRenderer3D OverLayRender = new PrimitivesRenderer3D();
            public List<TexturedBatch3D> OverLayBatchs = new List<TexturedBatch3D>();
            public int face = 0;
            public Color BgColor;
            public FaceDraw(int f,Color color)
            {
                BgColor = color;
                face = f;
            }
            public void Dispose()
            {
                foreach (var b in OverLayBatchs)
                {
                    //释放资源
                    b.Texture.Dispose();
                }
                OverLayRender.Clear();
            }
        }
        public static Dictionary<Point3, FaceDraw> DrawFaces = new Dictionary<Point3, FaceDraw>();
        public static float lightOn = 0f;
        public Texture2D ElectrictOverLay = ContentManager.Get<Texture2D>("Mekiasm/Gui/Overlay/energy");
        public Texture2D FluidOverLay = ContentManager.Get<Texture2D>("Mekiasm/Gui/Overlay/fluids");
        public Texture2D GasOverLay = ContentManager.Get<Texture2D>("Mekiasm/Gui/Overlay/gases");
        public Texture2D ItemsOverLay = ContentManager.Get<Texture2D>("Mekiasm/Gui/Overlay/items");

        private static List<Action> DispatchActions = new List<Action>();

        public static void Dispatch(Action action) { DispatchActions.Add(action); }

        public static void Dispatch()
        {
            foreach (Action action in DispatchActions) action?.Invoke();
            DispatchActions.Clear();
        }

        static PrimitivesRenderer2D primitivesRenderer2D = new PrimitivesRenderer2D();

        public override bool ClothingProcessSlotItems(ComponentPlayer componentPlayer, Block block, int slotIndex, int value, int count)
        {
            return base.ClothingProcessSlotItems(componentPlayer, block, slotIndex, value, count);
        }

        public static void DropBox(Widget parent, string text)
        {
            DropBoxUtil.DropBox.Show(parent, new DropBoxUtil.DropBox.BoxConfig() { Text = text });
        }

        public void DebugView()
        {
            var input = ScreensManager.CurrentScreen.Input;
            if (input.MousePosition.HasValue)
            {
                ScreensManager.CurrentScreen.HitTestGlobal(input.MousePosition.Value, w => {
                    var WindowSize = Display.Viewport.Rectangle.Size;
                    FlatBatch2D flat = primitivesRenderer2D.FlatBatch();
                    FontBatch2D font = primitivesRenderer2D.FontBatch(LabelWidget.BitmapFont);
                    System.Text.StringBuilder builder = new System.Text.StringBuilder();
                    builder.Append($"{w.GetType().FullName}  {w.ActualSize.X}x{w.ActualSize.Y}\nMargin:{w.Margin}\nName:{w.Name}\n");
                    if (w is ContainerWidget c)
                    {
                        builder.Append("ChildrenList:\n");
                        foreach (var it in c.Children)
                        {
                            builder.Append($"{it.GetType().FullName}  ///  {it.Name}\n");
                        }
                    }

                    string text = builder.ToString();
                    var fontPosition = Vector2.Zero;
                    Vector2 textBox = LabelWidget.BitmapFont.MeasureText(text, new Vector2(0.6f), Vector2.Zero);

                    if (w.GlobalBounds.Min.Y - textBox.Y >= 0)
                    {
                        //可以放上方
                        fontPosition.Y = w.GlobalBounds.Min.Y - textBox.Y;
                    }
                    else
                    {
                        if (w.GlobalBounds.Max.Y + textBox.Y <= WindowSize.Y)
                        {
                            //可以放下方
                            fontPosition.Y = w.GlobalBounds.Max.Y;
                        }
                        else fontPosition.Y = WindowSize.Y - textBox.Y;
                    }


                    if (w.GlobalBounds.Max.X + textBox.X <= WindowSize.X)
                    {
                        //可以放右边
                        fontPosition.X = w.GlobalBounds.Max.X;
                    }
                    else
                    {
                        if (w.GlobalBounds.Min.X - textBox.X >= 0)
                        {
                            //可以放左边
                            fontPosition.X = w.GlobalBounds.Min.X - textBox.X;
                        }
                        else fontPosition.X = 0;
                    }


                    flat.QueueQuad(fontPosition, fontPosition + textBox, 0f, Color.White);
                    font.QueueText(text, fontPosition, 1f, Color.Black, TextAnchor.Default, new Vector2(0.5f), Vector2.Zero);

                    var outterTopLeft = w.GlobalBounds.Min;
                    var outterTopRight = new Vector2(w.GlobalBounds.Max.X, w.GlobalBounds.Min.Y);
                    var outterBottomRight = w.GlobalBounds.Max;
                    var outterBottomLeft = new Vector2(w.GlobalBounds.Min.X, w.GlobalBounds.Max.Y);

                    var innerTopLeft = outterTopLeft + w.Margin;
                    var innerTopRight = outterTopRight + new Vector2(-w.Margin.X, w.Margin.Y);
                    var innerBottomRight = outterBottomRight - w.Margin;
                    var innerBottomLeft = outterBottomLeft + new Vector2(w.Margin.X, -w.Margin.Y);

                    var paddingColor = new Color(0, 0, 128, 44);
                    var fillColor = new Color(0, 128, 0, 44);
                    if (w.Margin != Vector2.Zero)
                    {
                        var v1 = w.GlobalBounds.Min + w.Margin;
                        var v2 = w.GlobalBounds.Max - w.Margin;

                        flat.QueueQuad(outterTopLeft, outterTopRight, new Vector2(outterTopRight.X, innerTopRight.Y), new Vector2(outterTopLeft.X, innerTopLeft.Y), 1f, paddingColor);
                        flat.QueueQuad(new Vector2(outterBottomLeft.X, innerBottomLeft.Y), new Vector2(outterBottomRight.X, innerBottomRight.Y), outterBottomRight, outterBottomLeft, 1f, paddingColor);
                        flat.QueueQuad(new Vector2(outterTopLeft.X, innerTopLeft.Y), innerTopLeft, innerBottomLeft, new Vector2(outterBottomLeft.X, innerBottomLeft.Y), 1f, paddingColor);
                        flat.QueueQuad(innerTopRight, new Vector2(outterTopRight.X, innerTopRight.Y), new Vector2(outterBottomRight.X, innerBottomRight.Y), innerBottomRight, 1f, paddingColor);

                        flat.QueueQuad(innerTopLeft, innerTopRight, innerBottomRight, innerBottomLeft, 1f, fillColor);
                    }
                    else
                    {
                        flat.QueueQuad(outterTopLeft, outterTopRight, outterBottomRight, outterBottomLeft ,1f, fillColor);
                    }
                    primitivesRenderer2D.Flush();
                    return true;
                });
            }
        }

        public override void __ModInitialize()
        {
            //Window.Frame += DebugView;
            ModsManager.RegisterHook("OnLoadingStart", this);
            ModsManager.RegisterHook("OnLoadingFinished", this);
            ModsManager.RegisterHook("OnProjectLoaded", this);
            ModsManager.RegisterHook("OnModelRendererDrawExtra", this);
            ModsManager.RegisterHook("OnXdbLoad", this);
            ModsManager.RegisterHook("GuiDraw", this);
            ModsManager.RegisterHook("GuiUpdate", this);
            ModsManager.RegisterHook("SetShaderParameter",this);
            ModsManager.RegisterHook("OnReadSpawnData", this);
            ModsManager.RegisterHook("OnSaveSpawnData", this);
            ModsManager.RegisterHook("AttackBody", this);
            ModsManager.RegisterHook("GetMaxInstancesCount",this);
            ModsManager.RegisterHook("ProjectXmlLoad", this);
            ModsManager.RegisterHook("OnProjectDisposed", this);
            ModsManager.RegisterHook("OnMinerDig", this);
            ModsManager.RegisterHook("GenerateChunkLightSources", this);
        }

        public override void GenerateChunkLightSources(DynamicArray<LightSource> lightSources, TerrainChunk chunk)
        {
            if (FlashLight.Last.HasValue)
            {
                var p = FlashLight.Last.Value;
                lightSources.Add(new LightSource() { X = p.X, Y = p.Y, Z = p.Z, Light = 15 });
            }
        }

        public override void OnMinerDig(ComponentMiner miner, TerrainRaycastResult raycastResult, ref float DigProgress, out bool Digged)
        {
            Digged = DigProgress == 1f;
            if (Digged)
            {
                var block = BlocksManager.Blocks[Terrain.ExtractContents(miner.ActiveBlockValue)];
                if (block is MekBlock mek)
                {
                    Digged = mek.OnDigged(raycastResult.Value, miner, raycastResult);
                }
            }
        }

        public override int GetMaxInstancesCount()
        {
            return 24;
        }

        public override void DeadBeforeDrops(ComponentHealth componentHealth, out bool Skip)
        {
            if (componentHealth.Health <= 0 && componentHealth.m_lastHealth > componentHealth.Health)
            {
                //概率掉落奇异植物
                var body = componentHealth.Entity.FindComponent<ComponentBody>();
                Vector3 position3 = (body.BoundingBox.Min + body.BoundingBox.Max) / 2f;
                if (ILibrary.random.Bool(0.2f)) ILibrary.SubsystemPickables.AddPickable(RunicBush.Index, 1, position3, null, null);
            }
            Skip = false;
        }
        
        public override bool AttackBody(ComponentBody target, ComponentCreature attacker, Vector3 hitPoint, Vector3 hitDirection, ref float attackPower, bool isMeleeAttack)
        {
            var targetLevel = target.Entity.FindComponent<ComponentNLevel>();
            if (attacker != null)
            {
                var attackerLevel = attacker.Entity.FindComponent<ComponentNLevel>();
                //计算伤害加成
                if (attackerLevel != null) attackPower *= attackerLevel.StrengthFactor;
            }
            if (targetLevel != null)
            {
                //计算免伤
                attackPower *=(1f - targetLevel.DefendFactor);
            }
            return false;
        }

        public override void OnReadSpawnData(Entity entity, SpawnEntityData spawnEntityData)
        {
            ComponentRobit robit = entity.FindComponent<ComponentRobit>();
            if (robit != null)
            {//解决机器人超出视野数据消失问题
                ValuesDictionary robitData = spawnEntityData.Data.GetValue("mek_robit",new ValuesDictionary());
                robit.Load(robitData, null);
            }
            else {
                var l = entity.FindComponent<ComponentNLevel>();
                if (l != null)
                {
                    l.Level = spawnEntityData.Data.GetValue("mek_level", 1f);
                }
            }
        }
        public override void OnSaveSpawnData(ComponentSpawn spawn, SpawnEntityData spawnEntityData)
        {
            ComponentRobit robit = spawn.Entity.FindComponent<ComponentRobit>();
            if (robit != null)
            {
                ValuesDictionary robitData = new ValuesDictionary();
                robit.Save(robitData, null);
                spawnEntityData.Data.SetValue("mek_robit", robitData);
            }
            else
            {
                var l = spawn.Entity.FindComponent<ComponentNLevel>();
                if (l != null)
                {
                    spawnEntityData.Data.SetValue("mek_level", l.Level);
                }
            }
        }

        public override void OnLoadingStart(List<Action> actions)
        {
            actions.Insert(0,MekiasmInit.init_);
        }

        public override void OnLoadingFinished(List<Action> loadingActions)
        {
            loadingActions.Add(delegate
            {
                for (int i = 1000; i < BlocksManager.Blocks.Length; i++)
                {
                    if (BlocksManager.Blocks[i] is MekBlock)
                        MekiasmInit.MekBlocks.Add(i, BlocksManager.Blocks[i] as MekBlock);
                }
            });
            loadingActions.Add(ILibrary.Init);
            loadingActions.Add(FluidSystem.InitRenders);
            loadingActions.Add(delegate {

                MekCraftingRecipe.MekRecipes.Clear();
                BlocksManager.Blocks[WaterBlock.Index].CraftingId = "water";//水
                BlocksManager.Blocks[MagmaBlock.Index].CraftingId = "magma";//岩浆
                BlocksManager.Blocks[CopperOreBlock.Index].CraftingId = "copper_ore";//铜矿
                BlocksManager.Blocks[IronOreBlock.Index].CraftingId = "iron_ore";//铁矿
                BlocksManager.Blocks[CoalOreBlock.Index].CraftingId = "coal_ore";//煤矿
                BlocksManager.Blocks[DiamondOreBlock.Index].CraftingId = "diamond_ore";//钻石矿
                BlocksManager.Blocks[GermaniumOreBlock.Index].CraftingId = "germanium_ore";//锗矿
                BlocksManager.Blocks[SaltpeterOreBlock.Index].CraftingId = "saltpeter_ore";//硝石
                BlocksManager.Blocks[SulphurOreBlock.Index].CraftingId = "sulphur_ore";//硫磺

                var campFireBlock = BlocksManager.Blocks[CampfireBlock.Index];
                campFireBlock.DefaultIsInteractive = true;
                var campfireBehavior = campFireBlock.Behaviors;
                //附加篝火行为
                if (string.IsNullOrEmpty(campfireBehavior))
                {
                    campfireBehavior = "MekCampfireBehavior";
                }
                else
                {
                    campfireBehavior = $"MekCampfireBehavior,{campfireBehavior}";
                }
                campFireBlock.Behaviors = campfireBehavior;
                foreach (var c in MekiasmInit.MekBlocks)
                {
                    foreach (var item in c.Value.blocks.Values)
                    {
                        if (item is Interface.IDynamicCraft p)
                        {
                            List<MekRecipe> mekRecipes = new List<MekRecipe>();
                            MekCraftingRecipe.MekRecipes.Add(p, mekRecipes);
                            p.GenerateRecipes(mekRecipes);
                        }
                        item.Initilize();
                    }
                }
            });
        }
        public override void OnProjectLoaded(Project project)
        {
        }
        public override void OnXdbLoad(XElement xElement)
        {
            IEnumerable<XElement> Folders = xElement.Element("DatabaseObjects").Elements();
            foreach (XElement folder in Folders)
            {
                if (folder.Attribute("Guid").Value == "5fcdf35f-7001-442c-883e-e0502b15d291")
                {
                    XElement creatures = folder.Element("Folder");
                    IEnumerable<XElement> CreaturesFolder = creatures.Elements();
                    foreach (XElement cre in CreaturesFolder)
                    {
                        //为所有生物模板加入Level组件
                        if (cre.Attribute("Guid").Value == "66a49cbb-cb12-4479-9b40-fbadd9db3425")
                        {//Animals
                            IEnumerable<XElement> EntityTemplates = cre.Elements();
                            foreach (XElement entityTemplate in EntityTemplates)
                            {
                                XElement LevelMem = new XElement("MemberComponentTemplate");
                                LevelMem.SetAttributeValue("Name", "Nlevel");
                                LevelMem.SetAttributeValue("InheritanceParent", "37732344-a8b5-d353-fcc6-8cc1ad197eae");
                                LevelMem.SetAttributeValue("Guid", Guid.NewGuid().ToString());
                                entityTemplate.Add(LevelMem);
                            }
                        }
                        else if (cre.Attribute("Guid").Value == "662d69f8-483c-4271-966b-da9cbb4f5042")
                        {//Abstract
                            IEnumerable<XElement> EntityTemplates = cre.Elements();
                            foreach (XElement entityTemplate in EntityTemplates)
                            {
                                if (entityTemplate.Attribute("Guid").Value == "4be6c1c5-d65d-4537-8a8b-a391969e6dc2")
                                {
                                    //为Player加入NBuff组件
                                    XElement LevelMem = new XElement("MemberComponentTemplate");
                                    LevelMem.SetAttributeValue("Name", "NBuff");
                                    LevelMem.SetAttributeValue("InheritanceParent", "99c7517d-3b66-486d-940a-3bdcd4790d82");
                                    LevelMem.SetAttributeValue("Guid", Guid.NewGuid().ToString());
                                    entityTemplate.Add(LevelMem);
                                    //为Player加入ExtraGui组件
                                    XElement ExtraGui = new XElement("MemberComponentTemplate");
                                    ExtraGui.SetAttributeValue("Name", "ExtraGui");
                                    ExtraGui.SetAttributeValue("InheritanceParent", "5473599b-1d00-4078-9ad3-cf7dfa833246");
                                    ExtraGui.SetAttributeValue("Guid", Guid.NewGuid().ToString());
                                    entityTemplate.Add(ExtraGui);
                                }
                            }
                        }
                    }
                }
            }
        }
        public override void OnModelRendererDrawExtra(SubsystemModelsRenderer modelsRenderer, SubsystemModelsRenderer.ModelData modelData, Camera camera, float? alphaThreshold)
        {
            ComponentModel componentModel = modelData.ComponentModel;
            if (!(componentModel is ComponentHumanModel))
            {
                ComponentNLevel componentNLevel = componentModel.Entity.FindComponent<ComponentNLevel>();
                //如果被骑乘就不显示
                if (componentNLevel != null && componentNLevel.Body.ParentBody == null)
                {
                    ComponentCreature componentCreature = componentNLevel.ComponentCreature;
                    ComponentHealth componentHealth = componentNLevel.ComponentHealth;
                    if (componentHealth == null) return;
                    Vector3 position = Vector3.Transform(componentCreature.ComponentBody.Position + 1.2f * Vector3.UnitY * componentCreature.ComponentBody.BoxSize.Y, camera.ViewMatrix);
                    if (position.Z < 0f)
                    {
                        Color color = Color.Lerp(Color.White, Color.Transparent, MathUtils.Saturate((position.Length() - 4f) / 3f));
                        if (color.A > 8)
                        {
                            float light = modelData.Light;
                            Color borderColor = Color.White * new Color(light, light, light, 255);
                            Color fontColor = new Color((1f - componentHealth.Health), componentHealth.Health, 0) * new Color(light, light, light);
                            Vector3 hpos = position + Vector3.UnitY * 0.3f;
                            Vector3 right = Vector3.TransformNormal(0.005f * Vector3.Normalize(Vector3.Cross(camera.ViewDirection, Vector3.UnitY)), camera.ViewMatrix);
                            Vector3 down = Vector3.TransformNormal(-0.005f * Vector3.UnitY, camera.ViewMatrix);
                            BitmapFont font = LabelWidget.BitmapFont;
                            FontBatch3D fontBatch3D = modelsRenderer.PrimitivesRenderer.FontBatch(font, 1, DepthStencilState.DepthRead, RasterizerState.CullNoneScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
                            FlatBatch3D flatBatch3D = modelsRenderer.PrimitivesRenderer.FlatBatch(1, DepthStencilState.DepthRead, RasterizerState.CullNoneScissor, BlendState.AlphaBlend);
                            //画线框
                            Vector3 p1 = hpos + new Vector3(-0.51f, 0.01f, 0f);
                            Vector3 p2 = hpos + new Vector3(0.51f, 0.01f, 0f);
                            Vector3 p3 = hpos + new Vector3(0.51f, -0.13f, 0f);
                            Vector3 p4 = hpos + new Vector3(-0.51f, -0.13f, 0f);
                            Vector3 p5 = hpos + new Vector3(-0.5f, 0f, 0f);
                            Vector3 p6 = hpos + new Vector3(-0.5f + componentHealth.Health, 0f, 0f);
                            Vector3 p7 = hpos + new Vector3(-0.5f + componentHealth.Health, -0.12f, 0f);
                            Vector3 p8 = hpos + new Vector3(-0.5f, -0.12f, 0f);
                            flatBatch3D.QueueLine(p1, p2, borderColor);
                            flatBatch3D.QueueLine(p2, p3, borderColor);
                            flatBatch3D.QueueLine(p3, p4, borderColor);
                            flatBatch3D.QueueLine(p4, p1, borderColor);
                            //画血条
                            flatBatch3D.QueueQuad(p5, p6, p7, p8,fontColor);
                            fontBatch3D.QueueText(componentCreature.DisplayName + " 等级" + Math.Floor(componentNLevel.Level), position, right, down, borderColor, TextAnchor.HorizontalCenter | TextAnchor.Bottom);
                        }
                    }
                }
            }
        }
        public override void GuiDraw(ComponentGui componentGui, Camera camera, int drawOrder)
        {
            var miner = componentGui.m_componentPlayer.ComponentMiner;
            TerrainRaycastResult? result = miner.Raycast<TerrainRaycastResult>(new Ray3(camera.ViewPosition, camera.ViewDirection), RaycastMode.Interaction, true, false, false);
            if (ILibrary.GetBasicValue(miner.ActiveBlockValue) == Configurator.Index && result.HasValue)
            {
                int Id = Terrain.ExtractContents(result.Value.Value);
                if (MekiasmInit.MekBlocks.TryGetValue(Id, out MekBlock mekBlock))
                {
                    if (mekBlock.GetDeviceType(result.Value.Value) != MekBlock.DeviceType.None)
                    {
                        ComponentBlockEntity blockEntity = ILibrary.SubsystemBlockEntities.GetBlockEntity(result.Value.CellFace.X, result.Value.CellFace.Y, result.Value.CellFace.Z);
                        if (blockEntity != null)
                        {
                            ComponentEnergyMachine machine = blockEntity.Entity.FindComponent<ComponentEnergyMachine>();
                            if (machine != null)
                            {
                                machine.MachineFaceConfig.TryGetValue(result.Value.CellFace.Face, out MachineFaceConfig config);
                                Color color = Color.Red;
                                Texture2D overlay;
                                switch (config.DeviceType)
                                {
                                    case MekBlock.DeviceType.Fluid: overlay = FluidOverLay; break;
                                    case MekBlock.DeviceType.Item: overlay = ItemsOverLay; break;
                                    case MekBlock.DeviceType.Gas: overlay = GasOverLay; break;
                                    case MekBlock.DeviceType.Electric: overlay = ElectrictOverLay; break;
                                    default: return;
                                }
                                if (config.MachineMode == MekBlock.MachineMode.IN)
                                {
                                    color = Color.Green;
                                }
                                DrawCubeFaceOverlay(componentGui.m_componentPlayer.GameWidget.ActiveCamera, result.Value.CellFace.Point, result.Value.CellFace.Face, color, overlay);
                            }
                        }
                    }
                }
            }
            ItemSystem.Draw(camera);
            SubsystemSingleChestDraw.Draw(camera);
            FluidSystem.Draw(camera);
            FluidSystem.UpdateRender();
        }
        /// <summary>
        /// 绘制覆盖面
        /// </summary>
        /// <param name="camera">相机</param>
        /// <param name="point">位置</param>
        /// <param name="face">面</param>
        /// <param name="bg">背景图</param>
        /// <param name="overlay">覆盖图</param>
        /// <param name="renderTarget2D">已经绘制好的图</param>
        public static void DrawCubeFaceOverlay(Camera camera, Point3 point, int face, Color bg, Texture2D overlay = null, RenderTarget2D renderTarget2D = null)
        {
            if (!DrawFaces.TryGetValue(point, out var draw))
            {
                draw = new FaceDraw(face, bg);
                DrawFaces.Add(point, draw);
                RenderTarget2D target2D1 = Display.RenderTarget;
                RenderTarget2D target2D;
                if (renderTarget2D == null)
                {
                    //渲染Texture
                    target2D = new RenderTarget2D(32, 32, 1, ColorFormat.Rgba8888, DepthFormat.None);
                    Display.RenderTarget = target2D;
                    PrimitivesRenderer2D primitivesRenderer2D = new PrimitivesRenderer2D();
                    FlatBatch2D flatBatch2D = primitivesRenderer2D.FlatBatch();
                    flatBatch2D.QueueQuad(Vector2.Zero, new Vector2(32), 0f, bg);
                    TexturedBatch2D texturedBatch2D = primitivesRenderer2D.TexturedBatch(overlay);
                    texturedBatch2D.QueueQuad(Vector2.Zero, new Vector2(32f), 0f, Vector2.Zero, Vector2.One, Color.White);
                    primitivesRenderer2D.Flush();
                    Display.RenderTarget = target2D1;

                }
                else
                {
                    target2D = renderTarget2D;
                }
                var geometry = new TerrainGeometry();
                SubsystemMekBlockBehavior.mekModelGenerator.GenerateCubeVerticesFace(BlocksManager.Blocks[1], 1, face, point.X, point.Y, point.Z, Color.White, geometry.GetGeometry(target2D).OpaqueSubsetsByFace);
                foreach (var d in geometry.GetGeometry(target2D).OpaqueSubsetsByFace)
                {
                    TexturedBatch3D textured = draw.OverLayRender.TexturedBatch(target2D, false, 1);
                    var subset = d;
                    for (int i = 0; i < subset.Indices.Count; i += 3)
                    {
                        int p1 = subset.Indices[i];
                        int p2 = subset.Indices[i + 1];
                        int p3 = subset.Indices[i + 2];
                        Vector3 v1 = new Vector3(subset.Vertices[p1].X, subset.Vertices[p1].Y, subset.Vertices[p1].Z);
                        Vector3 v2 = new Vector3(subset.Vertices[p2].X, subset.Vertices[p2].Y, subset.Vertices[p2].Z);
                        Vector3 v3 = new Vector3(subset.Vertices[p3].X, subset.Vertices[p3].Y, subset.Vertices[p3].Z);
                        Vector2 t1 = new Vector2(subset.Vertices[p1].Tx, subset.Vertices[p1].Ty) / 32767f;
                        Vector2 t2 = new Vector2(subset.Vertices[p2].Tx, subset.Vertices[p2].Ty) / 32767f;
                        Vector2 t3 = new Vector2(subset.Vertices[p3].Tx, subset.Vertices[p3].Ty) / 32767f;
                        Vector3 fix = new Vector3(CellFace.FaceToPoint3(face)) * 0.01f;
                        textured.QueueTriangle(v1 + fix, v2 + fix, v3 + fix, t1, t2, t3, Color.White);
                    }
                    draw.OverLayBatchs.Add(textured);
                }
            }
            draw.OverLayRender.Flush(camera.ViewProjectionMatrix, false, 20);
            if (face != draw.face || bg != draw.BgColor) { DisposeOverLay(point); }
        }
        public static void DisposeOverLay(Point3 point) {
            if (DrawFaces.TryGetValue(point, out var d)) { d.Dispose();DrawFaces.Remove(point); }
        
        }
        public override void GuiUpdate(ComponentGui componentGui)
        {
            ComponentPlayer m_componentPlayer = componentGui.m_componentPlayer;
            if (m_componentPlayer.ComponentInput.PlayerInput.Interact.HasValue)
            {
                Ray3 ray = m_componentPlayer.ComponentInput.PlayerInput.Interact.Value;
                BodyRaycastResult? raycastResult = m_componentPlayer.ComponentMiner.Raycast<BodyRaycastResult>(ray, RaycastMode.Interaction, false, true, false);
                if (raycastResult.HasValue)
                {
                    //点击机器人的界面
                    ComponentRobit energyMachine = raycastResult.Value.ComponentBody.Entity.FindComponent<ComponentRobit>();
                    if (energyMachine != null)
                    {
                        m_componentPlayer.ComponentGui.ModalPanelWidget = new RobitWidget(energyMachine, m_componentPlayer.ComponentMiner);
                    }
                }
            }
        }
        public override void ProjectXmlLoad(XElement xElement)
        {
            Window.Frame += Dispatch;
        }
        public override void OnProjectDisposed()
        {
            Window.Frame -= Dispatch;

            foreach (var c in SingleChestItem.RenderCache.Values)
            {
                c.Dispose();
            }
            SingleChestItem.RenderCache.Clear();
        }
    }
}
